package com.gksc.video.device;

import com.gksc.video.data.DeviceInfo;
import com.gksc.video.data.OpResInfo;
import com.sun.jna.ptr.ByteByReference;
import lombok.extern.slf4j.Slf4j;

import java.io.PipedOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @className: HCDevicePlay
 * @description: 海康威视设备播放取流实现类
 * @author: Liao.yx
 * @email: 1229053515@qq.com
 * @create: 2020年4月27日17:02:36
 * @copyRight: 2020 liaoyongxiang All rights reserved.
 **/
@Slf4j
public class HCDevicePlay {
    /**
     * 登录句柄
     */
    private Integer lUserId = -1;
    /**
     * 播放句柄
     */
    private Integer lHandle = -1;
    /**
     * 管道输出流
     */
    private PipedOutputStream ops;
    /**
     * 帧率
     */
    private Integer bitRate;

    public HCDevicePlay(PipedOutputStream ops, Integer bitRate) {
        this.ops = ops;
        this.bitRate = bitRate;
    }

    /**
     * 设备登录
     *
     * @param ip   设备ip
     * @param port 设备端口
     * @param user 设备用户
     * @param pwd  设备密码
     */
    private void loginDevice(String ip, short port, String user, String pwd) {
        boolean initFlag = HCNetSDK.INSTANCE.NET_DVR_Init();
        if (initFlag) {
            HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
            lUserId = HCNetSDK.INSTANCE.NET_DVR_Login_V30(ip, port, user, pwd, deviceInfo);
        } else {
            HCNetSDK.INSTANCE.NET_DVR_Cleanup();
            log.error("海康sdk初始化失败！错误码：{}", HCNetSDK.INSTANCE.NET_DVR_GetLastError());
        }
    }


    /**
     * 退出登录
     */
    private void logoutDevice() {
        HCNetSDK.INSTANCE.NET_DVR_Logout(lUserId);
        HCNetSDK.INSTANCE.NET_DVR_Cleanup();
    }

    /**
     * 停止回放
     */
    public void stop() {
        if (lHandle > 0) {
            boolean stopFlag = HCNetSDK.INSTANCE.NET_DVR_StopPlayBack(lHandle);
            if (!stopFlag) {
                HCNetSDK.INSTANCE.NET_DVR_Cleanup();
                log.error("停止回放失败！错误码：{}", HCNetSDK.INSTANCE.NET_DVR_GetLastError());
            }
        }
        if (lUserId > 0) {
            logoutDevice();
        }
    }

    /**
     * 回放视频
     *
     * @param device
     * @return
     */
    public OpResInfo<Integer> play(DeviceInfo device) {
        loginDevice(device.getDevIp(), device.getDevPort(), device.getUsername(), device.getPassword());
        if (lUserId < 0) {
            int errorCode = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            return new OpResInfo<>("海康sdk登录失败", errorCode, false);
        }
        lHandle = HCNetSDK.INSTANCE.NET_DVR_PlayBackByTime(lUserId, device.getChannel(), getHkTime(device.getStartTime()), getHkTime(device.getEndTime()), null);
        if (lHandle < 0) {
            int errorCode = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logoutDevice();
            log.error("海康sdk回放失败！错误码：{}", errorCode);
            return new OpResInfo<>("海康sdk回放失败", errorCode, false);
        }

        boolean callFlag = HCNetSDK.INSTANCE.NET_DVR_SetPlayDataCallBack(lHandle, new PlayDataCallBack(), 0);
        if (!callFlag) {
            int errorCode = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logoutDevice();
            log.error("海康sdk设置回调失败！错误码：{}", errorCode);
            return new OpResInfo<>("海康sdk设置回调失败", errorCode, false);
        }
        boolean startFlag = HCNetSDK.INSTANCE.NET_DVR_PlayBackControl(lHandle, HCNetSDK.NET_DVR_PLAYSTART, 0, null);
        if (!startFlag) {
            int errorCode = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logoutDevice();
            log.error("海康sdk回放失败！错误码：{}", errorCode);
            return new OpResInfo<>("海康sdk回放失败", errorCode, false);
        }
        // 控制历史回放拉流推流时的速度和直播一致
        boolean playFlag = HCNetSDK.INSTANCE.NET_DVR_PlayBackControl(lHandle, HCNetSDK.NET_DVR_SETSPEED, device.getBitRate() == null ? bitRate : device.getBitRate(), null);
        if (!playFlag) {
            int errorCode = HCNetSDK.INSTANCE.NET_DVR_GetLastError();
            logoutDevice();
            log.error("控制帧率失败！错误码：{}", errorCode);
            return new OpResInfo<>("控制帧率失败", errorCode, false);
        }
        log.info("设备device{}播放成功", device.toString());
        return new OpResInfo<>("", 0, true);
    }

    /**
     * 获取海康录像机格式的时间
     *
     * @param time
     * @return
     */
    private HCNetSDK.NET_DVR_TIME getHkTime(Date time) {
        HCNetSDK.NET_DVR_TIME strutTime = new HCNetSDK.NET_DVR_TIME();
        String str = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(time);
        String[] times = str.split("-");
        strutTime.dwYear = Integer.parseInt(times[0]);
        strutTime.dwMonth = Integer.parseInt(times[1]);
        strutTime.dwDay = Integer.parseInt(times[2]);
        strutTime.dwHour = Integer.parseInt(times[3]);
        strutTime.dwMinute = Integer.parseInt(times[4]);
        strutTime.dwSecond = Integer.parseInt(times[5]);
        return strutTime;
    }

    /**
     * @className: PlayDataCallBack
     * @description: 回放回调函数
     * @author: Liao.yx
     * @email: 1229053515@qq.com
     * @create: 2021年05月19日 09时29分
     * @copyRight: 2020 liaoyongxiang All rights reserved.
     **/
    class PlayDataCallBack implements HCNetSDK.FPlayDataCallBack {
        @Override
        public void invoke(int handle, int dwType, ByteByReference pBuffer, int dwBufSize, int pUser) {
            if (dwType == HCNetSDK.NET_DVR_STREAMDATA) {// 码流数据
                try {
                    if(dwBufSize == 0){
                        log.error("海康SDK获取的视频内容为空");
                    }
                    ops.write(pBuffer.getPointer().getByteArray(0, dwBufSize));
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("设备拉流handle={}异常{}", handle, e);
                }
            }
        }
    }

}
